﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Sims3Package;
using System.IO;

namespace Sims3Package.Wrapper
{
    public class VPXYResourceWrapper : Wrapper
    {
        public new static List<UInt32> ResourceTypes { get { return new List<uint>(mResourceTypes); } }
        private new static UInt32[] mResourceTypes = { 0x736884F1U };

        public ROCL Rocl { get; set; }
        public int Version { get; set; }
        public List<VPXYEntryData> DataList { get; set; }
        public byte TypeCode { get; set; }
        public float BoundingX1 { get; set; }
        public float BoundingY1 { get; set; }
        public float BoundingZ1 { get; set; }
        public float BoundingX2 { get; set; }
        public float BoundingY2 { get; set; }
        public float BoundingZ2 { get; set; }
        public int Unknown1 { get; set; }
        public byte ModularFlag { get; set; }
        public int FTPTIndex { get; set; }
        public TGIBlockList BlockList { get; set; }

        public VPXYResourceWrapper(Stream s) : base(s) { stream = s; if (s == null) return; stream.Position = 0; Parse(); }

        private void Parse()
        {
            BinaryReader r = new BinaryReader(stream);
            this.Rocl = new ROCL(stream);
            if (BitConverter.ToInt32(r.ReadBytes(4), 0) != BitConverter.ToInt32(Encoding.UTF8.GetBytes("VPXY"), 0))
                throw new InvalidDataException("This is not a VPXY file");
            this.Version = r.ReadInt32();

            this.BlockList = new TGIBlockList(stream);

            int count1 = r.ReadByte(); this.DataList = new List<VPXYEntryData>(count1);
            for (int i = 0; i < count1; i++)
            {
                switch(r.ReadByte())
                {
                    case 0x00:
                        this.DataList.Add(new VPXTEntryData1(stream));
                        break;
                    case 0x01:
                        this.DataList.Add(new VPXTEntryData2(stream));
                        break;
                }
            }

            this.TypeCode = r.ReadByte();
            this.BoundingX1 = r.ReadSingle();
            this.BoundingY1 = r.ReadSingle();
            this.BoundingZ1 = r.ReadSingle();
            this.BoundingX2 = r.ReadSingle();
            this.BoundingY2 = r.ReadSingle();
            this.BoundingZ2 = r.ReadSingle();

            this.Unknown1 = r.ReadInt32();
            this.ModularFlag = r.ReadByte();
            if (this.ModularFlag == 0x01) this.FTPTIndex = r.ReadInt32();

        }
        public override Stream UnParse()
        {
            MemoryStream s = new MemoryStream();
            BinaryWriter w = new BinaryWriter(s);
            this.Rocl.UnParse(s);
            long position = s.Position;
            w.Write(Encoding.UTF8.GetBytes("VPXY"));
            w.Write(this.Version);

            long TGI_TABLE_POSITION = s.Position;
            w.Write(0); w.Write(0);
            w.Write((byte)this.DataList.Count);
            foreach (VPXYEntryData data in this.DataList) data.UnParse(s);

            w.Write(this.TypeCode);
            w.Write(this.BoundingX1); w.Write(this.BoundingY1); w.Write(this.BoundingZ1);
            w.Write(this.BoundingX2); w.Write(this.BoundingY2); w.Write(this.BoundingZ2);

            w.Write(this.Unknown1);
            w.Write(this.ModularFlag); if (this.ModularFlag == 0x01) w.Write(this.FTPTIndex);

            long POSITION_TEMP = s.Position;
            s.Position = TGI_TABLE_POSITION;
            w.Write(POSITION_TEMP - position - 4);
            w.Write(4 + this.BlockList.Count * 16);
            s.Position = POSITION_TEMP;
            this.BlockList.UnParse(w);

            return s;
        }

        public override string Value
        {
            get
            {
                StringBuilder b = new StringBuilder();
                b.Append(this.Rocl.Value);
                b.AppendFormat("Version 0x{0:X8}\n", this.Version);
                b.AppendFormat("Data List: Count 0x{0:X2}\n", this.DataList.Count);
                for (int i = 0; i < this.DataList.Count; i++) b.AppendFormat("    [{0:X2}]:{1}", i, this.DataList[i].Value(this.BlockList));
                b.AppendFormat("Type Code: 0x{0:X2}\n", this.TypeCode);
                b.AppendFormat("Bounding Box X1: {0}\n", this.BoundingX1);
                b.AppendFormat("Bounding Box Y1: {0}\n", this.BoundingY1);
                b.AppendFormat("Bounding Box Z1: {0}\n", this.BoundingZ1);
                b.AppendFormat("Bounding Box X1: {0}\n", this.BoundingX2);
                b.AppendFormat("Bounding Box Y2: {0}\n", this.BoundingY2);
                b.AppendFormat("Bounding Box Z2: {0}\n", this.BoundingZ2) ;
                b.AppendFormat("Unknown1: 0x{0:X8}\n", this.Unknown1);
                b.AppendFormat("Modular Flag: 0x{0:X2}\n", this.ModularFlag);
                if (this.ModularFlag == 0x01) b.AppendFormat("FTPT Index: {0}\n", BlockList[this.FTPTIndex]);
                b.Append(BlockList.Value);
                return b.ToString();
            }
        }

        #region Sub-class
        public abstract class VPXYEntryData
        {
            public VPXYEntryData(Stream s) { }
            public abstract void UnParse(Stream s);
            public abstract int Type { get;}
            public abstract string Value(TGIBlockList list);
        }

        public class VPXTEntryData1 : VPXYEntryData
        {
            public override int Type { get { return 0; } }
            public byte msIndex { get; set; }
            public List<int> IndexList { get; set; }

            public VPXTEntryData1(Stream s) : base(s) { Parse(s); }

            private void Parse(Stream s)
            {
                BinaryReader r = new BinaryReader(s);
                this.msIndex = r.ReadByte();
                int count = r.ReadByte();
                this.IndexList = new List<int>(count);
                for (int i = 0; i < count; i++) this.IndexList.Add(r.ReadInt32());
            }
            public override string Value(TGIBlockList list)
            {
                StringBuilder b = new StringBuilder();
                b.AppendFormat("msIndex: 0x{0:X2}\n", this.msIndex);
                b.AppendFormat("      TGI Reference List: Count 0x{0:X2}\n", this.IndexList.Count);
                for (int i = 0; i < this.IndexList.Count; i++) b.AppendFormat("      [{0:X2}]: {1}\n", i, list[this.IndexList[i]]);
                return b.ToString();
            }
            

            public override void UnParse(Stream s)
            {
                BinaryWriter w = new BinaryWriter(s);
                w.Write(this.msIndex);
                w.Write((byte)this.IndexList.Count);
                foreach (int i in this.IndexList) w.Write(i);
            }
        }

        public class VPXTEntryData2 : VPXYEntryData
        {
            public int IndexID { get; set; }
            public override int Type { get { return 1; } }
            public VPXTEntryData2(Stream s) : base(s) { Parse(s); }

            private void Parse(Stream s)
            {
                BinaryReader r = new BinaryReader(s);
                this.IndexID = r.ReadInt32();            
            }
            public override string Value(TGIBlockList list)
            {
                StringBuilder b = new StringBuilder();
                b.AppendFormat("TGI Reference: {0}\n", list[IndexID]);
                return b.ToString();
            }

            public override void UnParse(Stream s)
            {
                BinaryWriter w = new BinaryWriter(s);
                w.Write(this.IndexID);
            }
        }
        #endregion
    }
}
